package com.yf.monitor.service;

import com.yf.monitor.ApiMonitorProperties;
import com.yf.monitor.entity.ApiRecord;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName ApiRecordService
 * @Description 服务类
 * @Author Scott.Yin
 * @Date 2025/8/21 17:30
 * @Version 1.0
 **/
@Service
@Slf4j
public class ApiRecordService {

    private final BlockingQueue<ApiRecord> recordQueue = new LinkedBlockingQueue<>(10000);

    // 单次批量最大大小（可配置，如 100）
    private final int batchMaxSize = 100;
    // 单次获取元素的超时时间（避免空轮询，如 500ms）
    private final long pollTimeout = 500;

    private volatile boolean running = true;

    @Autowired
    private TDengineService tdengineService;
    private final ApiMonitorProperties properties;

    @Autowired
    public ApiRecordService(TDengineService tdengineService,
                            ApiMonitorProperties properties) {
//        this.tdengineService = tdengineService;
        this.properties = properties;
        startConsumer();
    }

    @Async
    public void asyncSaveRecord(ApiRecord record) {
        try {
            // 设置时间戳
            record.setTimestamp(System.currentTimeMillis());

            // 将记录放入队列，如果队列满则等待
            boolean offered = recordQueue.offer(record, 100, TimeUnit.MILLISECONDS);
            if (!offered) {
                log.warn("记录队列已满，直接写入记录: {}", record.getApiName());
                // 可以选择直接存储或记录日志
                saveToTDengine(record);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("放入记录队列被中断", e);
        } catch (Exception e) {
            log.error("异步保存API记录异常", e);
        }
    }

    /**
     * 启动消费者线程
     */
    private void startConsumer() {
        Thread consumerThread = new Thread(() -> {
            while (running || !recordQueue.isEmpty()) {
                try {
//                    ApiRecord record = recordQueue.poll(100, TimeUnit.MILLISECONDS);
//                    if (record != null) {
//                        saveToTDengine(record);
//                    }
                    List<ApiRecord> batch = batchTake();
                    if (!batch.isEmpty()) {
                        // 执行批量业务逻辑（如批量插入 TDengine）
                        saveBatchToTDengine(batch);
                        log.info("批量处理完成，本次处理条数：{}", batch.size());
                    }
                    //TODO 可不等待？
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    log.warn("记录消费者线程被中断", e);
                    break;
                } catch (Exception e) {
                    log.error("处理记录异常", e);
                }
            }
        }, "Record-Consumer-Thread");

        consumerThread.setDaemon(true);
        consumerThread.start();
    }

    @PreDestroy
    public void shutdown() {
        running = false;
        log.warn("记录消费者线程自动销毁");
    }

    /**
     * 同步写入
     **/
    public void saveRecord(ApiRecord record) {
        try {
            record.setTimestamp(System.currentTimeMillis());
            saveToTDengine(record);
        } catch (Exception e) {
            log.error("同步保存API记录异常", e);
        }
    }

    /**
     * 保存到TDengine
     */
    private void saveToTDengine(ApiRecord record) {
        tdengineService.insertApiRecord(record);
    }

    /**
     * 批量保存到TDengine
     */
    private void saveBatchToTDengine(List<ApiRecord> records) {
        tdengineService.insertBatchApiRecord(records);
    }

    /**
     * 批量取出队列数据（每次最多取 batchMaxSize 个）
     * @return 批量数据列表（可能为空，需外部判断）
     * @throws InterruptedException 线程中断异常（需外部处理）
     */
    public List<ApiRecord> batchTake() throws InterruptedException {
        List<ApiRecord> batchList = new ArrayList<>(batchMaxSize); // 初始化容量，减少扩容开销

        // 1. 先尝试无阻塞获取最多 batchMaxSize 个元素（快速获取已有元素）
        int drained = recordQueue.drainTo(batchList, batchMaxSize);
        if (drained >= batchMaxSize) {
            return batchList; // 已取满批量大小，直接返回
        }

        // 2. 若未取满，阻塞等待新元素（最多等 pollTimeout 时间）
        ApiRecord record = recordQueue.poll(pollTimeout, TimeUnit.MILLISECONDS);
        if (record != null) {
            batchList.add(record);
            // 3. 再次尝试无阻塞获取剩余元素（补充到批量大小）
            recordQueue.drainTo(batchList, batchMaxSize - batchList.size());
        }

        // 返回当前收集到的批量数据（可能少于 batchMaxSize，甚至为空）
        return batchList;
    }
}
